package com.example.graduation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.graduation.entity.*;
import com.example.graduation.exception.MyException;
import com.example.graduation.mapper.*;
import com.example.graduation.service.ShoppingCartService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.graduation.util.JwtUtil;
import com.example.graduation.vo.*;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xyc
 * @since 2022-02-11
 */
@Service
public class ShoppingCartServiceImpl extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private ShoppingCartMapper shoppingCartMapper;

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ShopMapper shopMapper;

    /**
     * 构建私人购物车列表名称，也就是redis的key名称
     */
    private final static String CART_REDIS_KEY_TEMPLATE = "cart_%d";

    /**
     * 创建商店名称
     */
    private final static String SHOP_REDIS_KEY_TEMPLATE = "shop_%d";


    @Resource
    private JwtUtil jwtUtil;


    /**
     * 创建gson对象
     */
    private Gson gson = new Gson();


    /**
     * 加入订单
     * 购买商品时，将商品信息分别插入购物车，用户订单，和减库存，并将购买的内容返回至前端
     * 其实我觉得不需要返回List<Goods>
     *
     * @param shopId
     * @param userId
     * @param goodsIdAndCount
     * @return {@link ShopCartVo}
     * @author xieyucan
     * CreateDate 2022/3/3 18:28
     */
    @Override
    public ShopCartVo addOrderList(Integer shopId, Integer userId, String goodsIdAndCount) {
        try {
            ShopCartVo shopCartVo = new ShopCartVo();
            String uuid = String.valueOf(UUID.randomUUID());
            shopCartVo.setOrderId(uuid);
            shopCartVo.setShopId(shopId);
            shopCartVo.setUserId(userId);
            //记录本次购买了多少钱
            double total = 0;
            int allCount = 0;
            //用来收集goods的信息
            List<Goods> list = new ArrayList<>();

            String[] split = goodsIdAndCount.split(",");
            for (int i = 0; i < split.length - 1; i += 2) {
                //逐个找出商品信息
                Goods goods = goodsMapper.selectGoodsById(shopId, Integer.parseInt(split[i]));
                //加多一次判断，防止别人修改我的前端返回的数据count值，导致我库存<0
                Integer count = goods.getCount();
                //数据正常的情况下，我们就可以减库存了,和插入ShoppingCart数据库表的内容
                if (count > Integer.parseInt(split[i + 1])) {
                    count -= Integer.parseInt(split[i + 1]);
                    goodsMapper.updateCount(shopId, userId, count);
                    ShoppingCart shoppingCart = new ShoppingCart();
                    shoppingCart.setCou(Integer.parseInt(split[i + 1]));
                    shoppingCart.setCreateTime(System.currentTimeMillis() / 1000);
                    shoppingCart.setGoodsId(Integer.parseInt(split[i]));
                    shoppingCart.setOldPrice(goods.getOldprice());
                    shoppingCart.setStatus(0);
                    shoppingCart.setOrderId(System.currentTimeMillis());
                    shoppingCart.setUserId(userId);
                    shopCartVo.setShopId(shopId);
                    Integer num = shoppingCartMapper.insertShopCart(shoppingCart);
                    allCount += num;
                    total += goods.getNewprice();
                    list.add(goods);
                } else {
                    throw new MyException("库存出现错误");
                }
            }
            //创建order对象
            Torder torder = new Torder();
            torder.setCreateTime(System.currentTimeMillis() / 1000);
            torder.setOrderId(System.currentTimeMillis());
            torder.setStatus(0);
            torder.setTotal(total);
            torder.setShuliang(allCount);
            //向数据库表中添加订单信息
            orderMapper.insert(torder);
            shopCartVo.setList(list);
            return shopCartVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(e.getMessage());
        }
    }


    /**
     * 加入商品购物车列表中，在这里加到redis中，到时候查询也从redis中查询
     * 在这里需要注意添加一个选择的boolean值
     * <p>
     * 在这里选择使用redis的hash数据结构
     * 他的数据结构为 redisKey goodsId GoodsVo
     *
     * @param shopId
     * @param goodsId
     * @param addCount
     * @param token    根据token获取用户id
     * @author xieyucan
     * CreateDate 2022/3/22 10:33
     */
    @Override
    public CartVo addCartList(Integer shopId, Integer goodsId, Integer addCount, String token) {
        try {
            //先把商品查询出来
            QueryWrapper<Goods> wrapper = new QueryWrapper<>();
            wrapper.eq("goods_id", goodsId);
            Goods goods = goodsMapper.selectOne(wrapper);
            if (goods == null) {
                throw new MyException("商品不存在");
            }
            if (goods.getStatus() != 0) {
                throw new MyException("商品已停止销售");
            }
            if (goods.getCount() <= 0) {
                throw new MyException("商品库存不足");
            }
            //构建Redis的hash数据结构
            HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
            int userId = jwtUtil.getUserIdByToken(token);
            //获取redisKey的值，在这里我利用值的替换模式创建，比如我是cart_%d,%d则为可替换的位置
            String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, userId);
            //获取到该商品id在redis存储的值
            String value = opsForHash.get(redisKey, String.valueOf(goods.getGoodsId()));
            //创建redis单条商品列表信息
            GoodsVo goodsVo;

            //如果他的值为空，则添加到购物车，如果值不为空，则修改购物车
            if (StringUtils.isEmpty(value)) {
                goodsVo = new GoodsVo(goods.getGoodsId(),
                        goods.getShopId(),
                        goods.getNewprice(),
                        goods.getStatus(),
                        goods.getGoodsname(),
                        addCount,
                        goods.getPhoto(),
                        sumTotal(addCount, goods.getNewprice()),
                        true);
                String goodsVoValue = String.valueOf(goodsVo);
                opsForHash.put(redisKey, String.valueOf(goods.getGoodsId()), gson.toJson(goodsVo));
            } else {
                goodsVo = gson.fromJson(value, GoodsVo.class);
                Integer addCount1 = goodsVo.getAddCount();
                goodsVo.setAddCount(addCount + addCount1);

                opsForHash.put(redisKey, String.valueOf(goods.getGoodsId()), gson.toJson(goodsVo));
            }
            return cartList(userId);
        } catch (Exception e) {
            log.error("添加失败");
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }


    /**
     * 获取用户个人购物车列表,
     * 在这里我把数据就行了整理，我把直接存储的购物车列表转换为 一个商店对应该商店中的商品列表
     *
     * @param userId
     * @return {@link CartVo}
     * @author xieyucan
     * CreateDate 2022/3/22 15:28
     */
    public CartVo cartList(Integer userId) {
        try {
            CartVo cartVo = new CartVo();
            HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
            //获取redisKey的值，在这里我利用值的替换模式创建，比如我是cart_%d,%d则为可替换的位置
            String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, userId);
            Map<String, List<GoodsVo>> map = new HashMap<>();
            //取出该用户的购物车列表，并对数据就行整理
            Map<String, String> entries = opsForHash.entries(redisKey);
            boolean selectAll = true;
            //创建Set数据结构，用于划分用户购物车中的商店
            Set<Integer> set = new HashSet<>();
            //商品总数量
            int count = 0;
            //商品总价格
            Double totalPrice = 0.0;
            for (Map.Entry<String, String> entry : entries.entrySet()) {
                GoodsVo goodsVo = gson.fromJson(entry.getValue(), GoodsVo.class);
                Integer shopId = goodsVo.getShopId();
                //判断这个商店id是否存在于set中，存在则寻找回该商店的购物车，
                // 不存在则直接添加到购物车列表中
                if (!set.contains(shopId)) {
                    set.add(shopId);
                    List<GoodsVo> list = new ArrayList<>();
                    list.add(goodsVo);
                    String shopKey = String.format(SHOP_REDIS_KEY_TEMPLATE, shopId);
                    map.put(shopKey, list);
                } else {
                    String shopKey = String.format(SHOP_REDIS_KEY_TEMPLATE, shopId);
                    List<GoodsVo> list = map.get(shopKey);
                    list.add(goodsVo);
                    map.put(shopKey, list);
                }

                if (!goodsVo.getIsSelect()) {
                    selectAll = false;
                }
                //只计算选中的商品数量和总消费
                if (goodsVo.getIsSelect()) {
                    totalPrice += goodsVo.getSumPrice();
                    count += goodsVo.getAddCount();
                }
            }
            cartVo.setCount(count);
            cartVo.setTotalPrice(totalPrice);
            cartVo.setSelectAll(selectAll);
            cartVo.setMap(map);
            return cartVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }


    /**
     * 计算单个商品总花费
     *
     * @param addCount
     * @param newPrice
     * @return
     */
    private Double sumTotal(Integer addCount, Double newPrice) {
        Double sum = addCount * newPrice;
        return sum;
    }


    /**
     * 删除购物车中的商品列表
     *
     * @param token
     * @param goodsId
     * @return {@link CartVo}
     * @author xieyucan
     * CreateDate 2022/3/22 15:48
     */
    @Override
    public CartVo deleteGoodsVo(String token, Integer goodsId) {
        try {
            HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
            //通过jwt获取用户id
            int userId = jwtUtil.getUserIdByToken(token);
            String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, userId);
            //获取到该条购物车列表
            String value = opsForHash.get(redisKey, String.valueOf(goodsId));
            //存在于redis中的购物车列表里面的数据可能不存在，对此需要进行判断
            if (StringUtils.isEmpty(value)) {
                throw new MyException("操作失败");
            }
            opsForHash.delete(redisKey, String.valueOf(goodsId));
            return cartList(userId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }


    /**
     * 用户更新购物车列表
     *
     * @param token
     * @param goodsId
     * @param cartUpdateVo
     * @return {@link CartVo}
     * @author xieyucan
     * CreateDate 2022/3/22 16:11
     */
    @Override
    public CartVo updateCartVo(String token, Integer goodsId, CartUpdateVo cartUpdateVo) {
        try {
            HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
            int userId = jwtUtil.getUserIdByToken(token);
            String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, userId);
            String value = opsForHash.get(redisKey, String.valueOf(goodsId));
            if (StringUtils.isEmpty(value)) {
                throw new MyException("操作失败");
            }
            GoodsVo goodsVo = gson.fromJson(value, GoodsVo.class);
            if (cartUpdateVo.getCount() != null && cartUpdateVo.getCount() >= 0) {
                goodsVo.setAddCount(cartUpdateVo.getCount());
            }
            if (cartUpdateVo.getIsSelect() != null) {
                goodsVo.setIsSelect(cartUpdateVo.getIsSelect());
            }
            opsForHash.put(redisKey, String.valueOf(goodsId), gson.toJson(goodsVo));
            return cartList(userId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException("操作失败");
        }

    }


    /**
     * 购买商品
     *
     * @param token
     * @param goodsId
     * @param count
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    public Boolean buy(String token, Integer goodsId, Integer count) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            QueryWrapper<Goods> wrapper = new QueryWrapper<>();
            QueryWrapper<Torder> wrapper1 = new QueryWrapper<>();
            QueryWrapper<ShoppingCart> wrapper2 = new QueryWrapper<>();
            wrapper.eq("goods_id", goodsId);
            Goods goods = goodsMapper.selectOne(wrapper);
            if (goods.getCount() < count) {
                throw new MyException("库存不足");
            }
            goods.setCount(goods.getCount() - count);
            goodsMapper.update(goods, wrapper);
            Torder torder = new Torder();
            torder.setCreateTime(System.currentTimeMillis());
            torder.setOrderId(System.currentTimeMillis());
            torder.setShopId(goods.getShopId());
            torder.setCreateTime(System.currentTimeMillis());
            torder.setTotal(count * goods.getNewprice());
            torder.setShuliang(count);
            torder.setStatus(3);
            torder.setUserId(userId);
            orderMapper.insert(torder);

            ShoppingCart shoppingCart = new ShoppingCart();
            shoppingCart.setUserId(userId);
            shoppingCart.setGoodsId(goodsId);
            shoppingCart.setCou(count);
            shoppingCart.setShopId(goods.getShopId());
            shoppingCart.setOrderId(torder.getOrderId());
            shoppingCart.setOldPrice(goods.getNewprice());
            shoppingCart.setCreateTime(System.currentTimeMillis());
            shoppingCartMapper.insert(shoppingCart);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 查询用户的订单列表
     *
     * @param token
     * @return
     */
    public List<Torder> findOrderByToken(String token) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            QueryWrapper<Torder> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId).orderByDesc("create_time");
            List<Torder> torders = orderMapper.selectList(wrapper);
            for (Torder torder : torders) {
                Shop shop = shopMapper.selectById(torder.getShopId());
                torder.setShop(shop);
                QueryWrapper<ShoppingCart> wrapper1 = new QueryWrapper<>();
                wrapper1.eq("order_id", torder.getOrderId());
                List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectList(wrapper1);
                ArrayList<Goods> goodsArrayList = new ArrayList<>();
                for (ShoppingCart shoppingCart : shoppingCarts) {
                    QueryWrapper<Goods> wrapper2 = new QueryWrapper<>();
                    wrapper2.eq("goods_id", shoppingCart.getGoodsId());
                    Goods goods = goodsMapper.selectOne(wrapper2);
                    goodsArrayList.add(goods);
                }
                torder.setList(goodsArrayList);
            }
            return torders;
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException("订单查询失败");
        }

    }


    /**
     * 查询商家的订单列表
     *
     * @param token
     * @return
     */
    public List<Torder> findShopOrder(String token) {
        int userId = jwtUtil.getUserIdByToken(token);
        QueryWrapper<Shop> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        Shop shop = shopMapper.selectOne(wrapper);
        Integer shopId = shop.getShopId();

        QueryWrapper<Torder> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("shop_id", shopId).orderByDesc("create_time");
        List<Torder> torders = orderMapper.selectList(wrapper1);

        for (Torder torder : torders) {

            User user = userMapper.searchById(torder.getUserId());
            torder.setUser(user);
            QueryWrapper<ShoppingCart> wrapper2 = new QueryWrapper<>();
            wrapper2.eq("order_id", torder.getOrderId());
            List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectList(wrapper2);
            ArrayList<Goods> goodsArrayList = new ArrayList<>();
            for (ShoppingCart shoppingCart : shoppingCarts) {
                QueryWrapper<Goods> wrapper3 = new QueryWrapper<>();
                wrapper2.eq("goods_id", shoppingCart.getGoodsId());
                Goods goods = goodsMapper.selectOne(wrapper3);
                goodsArrayList.add(goods);
            }
            torder.setList(goodsArrayList);
        }

        return torders;
    }


    /**
     * 根据订单号，查询订单详情
     *
     * @param orderId
     * @return
     */
    public Torder selectOrderById(Long orderId) {
        QueryWrapper<Torder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        Torder torder = orderMapper.selectOne(queryWrapper);
        QueryWrapper<ShoppingCart> wrapper = new QueryWrapper<>();

        wrapper.eq("order_id", orderId);
        Shop shop = shopMapper.selectById(torder.getShopId());
        torder.setShop(shop);
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectList(wrapper);
        ArrayList<Goods> goods = new ArrayList<>();
        for (ShoppingCart shoppingCart : shoppingCarts) {
            QueryWrapper<Goods> wrapper1 = new QueryWrapper<>();
            wrapper1.eq("goods_id", shoppingCart.getGoodsId());
            Goods goods1 = goodsMapper.selectOne(wrapper1);
            goods.add(goods1);
        }
        torder.setList(goods);
        return torder;
    }


    /**
     * 购买商品
     *
     * @param token
     * @param goodsInfo
     * @return
     */
    public Boolean buyGoods(String token, String goodsInfo) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            Torder torder = new Torder();
            long orderId = System.currentTimeMillis();
            torder.setOrderId(orderId);
            torder.setUserId(userId);
            Integer shopId = null;
            String[] split = goodsInfo.split(",");
            int len = split.length;
            double count = 0;
            Calendar instance = Calendar.getInstance();
            int month = instance.get(Calendar.MONTH) + 1;
            for (int i = 0; i < len; i = i + 2) {
                Goods goods = goodsMapper.selectById(split[i + 1]);
                shopId = goods.getShopId();
                ShoppingCart cart = new ShoppingCart();
                cart.setCou(Integer.valueOf(split[i]));
                cart.setGoodsId(Integer.valueOf(split[i + 1]));
                cart.setOrderId(orderId);
                cart.setStatus(0);
                cart.setCreateTime(orderId);
                cart.setOldPrice(goods.getNewprice());
                cart.setShopId(goods.getShopId());
                cart.setMon(month);
                cart.setUserId(userId);
                shoppingCartMapper.insert(cart);
                count += Integer.valueOf(split[i]) * goods.getNewprice();
            }
            torder.setShopId(shopId);
            torder.setTotal(count);
            torder.setStatus(2);
            orderMapper.insert(torder);
            return true;
        } catch (Exception e) {
            throw new MyException(e.getMessage());
        }

    }


    public List<All> findRecord(Integer mon, String token) {
        int userId = jwtUtil.getUserIdByToken(token);
        QueryWrapper<Shop> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        Shop shop = shopMapper.selectOne(wrapper);
        List<Yigon> record = shoppingCartMapper.findRecord();
        ArrayList<All> list = new ArrayList<>();
        for (Yigon yigon : record) {
            Goods goods = goodsMapper.selectById(yigon.getGoods_id());
            All all = new All();
            all.setGoods(goods);
            all.setYigon(yigon);
            list.add(all);
        }
        return list;
    }

}
